#pragma once

#include "IRenderer.h"
#include "Cvars.h"
#include "Color.h"
#include "Material.h"

class SWRenderer : public IRenderer
{
public:
	enum eDrawType {
		WIREFRAME,
		FILL,
	};

	enum eShadeType {
		FLAT,
		GOURARD,
		PHONG,
	};

public:
	SWRenderer(int width = 512, int height = 512);

private:
	void initOpenGL();

	void createBuffers();

	void createOpenGLBuffer();	

public:
	virtual void resize();

	virtual void startScene();

	virtual void endScene();

	virtual void setModelTransform(const Mat4& m);

	virtual void drawPixel(int x, int y, int argb = WHITE);

	virtual void drawLine(const Vec3& v1, const Vec3& v2, int argb = WHITE);

	virtual void drawTriangle(const Vec3& v1, const Vec3& v2, const Vec3& v3);

	virtual void setCamera(CameraPtr camera);

private:
	void bresenham(int x1, int y1, int x2, int y2, int argb);

	void fillTriangle(const Vec3& v1, const Vec3& v2, const Vec3& v3);

	void shadePixel();

	Vec4 transformToWorld(const Vec3& v);

	Vec4 project(const Vec4& vh);

	Vec2 transformToView(const Vec4& v);

	bool clip(const Vec3& v);

	bool cull(const Vec4& v1, const Vec4& v2, const Vec4& v3);

private:
	CvarPtr _drawType;
	CvarPtr _shadeType;
	CvarPtr _wireframeColor;
	CvarPtr _width;
	CvarPtr _height;
	CvarPtr _clip;
	CvarPtr _useGlut;

	CameraPtr _camera;

	Mat4 _modelTransform;
	MaterialPtr _modelMeterial;

	vector<float> _backBuffer; // 3*width*height
	vector<float> _zbuffer; // width*height	

	int _initialWidth;
	int _initialHeight;

	unsigned int glScreenTex; // OpenGL
	unsigned int glScreenVtc; // OpenGL
};
